home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------------
- -----------------------------------------------------------------------------------
- SWTranslucentBlitters.c
-
- by Brian Roddy
-
- 4/13/97
-
- Routines for blitting translucent sprites in 8 bit or in 16 bit mode. Both versions
- require a lookup table to work properly. These lookup tables need to be initialized
- before being used. To initialize the 16 bit version, call
-
- err = SWCreate16BitTranslucencyTable();
-
- This creates a table which supports 30 levels of translucency and is small. The 8-bit
- table is much bigger. It requires 256 * 256 bytes (or 64K) of memory for each level
- of translucency. It also takes a relatively long time to compute. For this reason
- we have a number of functions to allow creating these tables in advance and saving them
- in the resource fork so they can be loaded quickly. By default you can call:
-
- err = SWLoadOrCreate8BitTranslucencyTable(numLevelsOfTranslucency);
-
- This single purpose function will try and load the table from a resource. If it
- does not exist, it will create the table and save it to the resource fork before continuing.
- This means that the first time you run the program, it will be slow and will compute
- this and save it. Next time you run the program it can just load it and thus will
- start up quickly. Note that you can go into ResEdit and copy a TTAB resource that
- has been computed and paste it into your project's resource file. This way, it will
- automatically be copied into your application's resource fork at link timeand therefore
- will never have to be computed. (To reiterate, you run your program first. This
- generates the computed table and stores it in the TTAB resource. You copy this resource
- into your project's resource file. From then on this TTAB will get copied to your
- application so you won't have to wait for it to be computed each time you recompile
- and run.)
-
- More detailed functions for manipulating these tables exist. See the source code
- for more details in the comments.
-
-
- Once you've called initialized the table or tables, you can set a Sprite's translucency
- level with:
-
- SWSetSpriteTranslucencyLevel(mySpritePtr, 6)
-
- where mySpritePtr is a SpritePtr and 6 is a byte specifying the translucency level.
- This level is a number from 1 to the number of Levels, where 1 is barely
- visible and a higher number is more opaque. If a level of any other value (e.g. 0
- or >= number of levels) is specified, the Sprite is considered fully opaque and is
- thus blitted normally.
-
- You can find a sprite's level of translucency with
-
- SWGetSpriteTranslucencyLevel(mySpritePtr)
-
- which will return the level as a byte, or 0 if the sprite is opaque.
-
- IMPORTANT: The translucent blitters and idle Sprites do not mix! This means that each
- translucent Sprite should have a MoveProc or FrameProc that is called every frame that
- sets the Sprite's needsToBeDrawn flag to true.
-
-
- -----------------------------------------------------------------------------------
- Implementation Notes:
-
- The 8-bit blitter is fairly optimal. There is some inline assembly to create four
- pixel longs in a minimal number of operations. Note that as the processor is much
- faster than the bus, we spend a couple extra cycles to create this long so all
- four can be passed at once.
-
- The 16-bit blitter is extremely optimized. The bulk is written in assembly and uses
- a lookup table.
-
- N.B.: Blitters are modified versions of blitters from SpriteWorld 2
-
- This source code is available for free use.
- -----------------------------------------------------------------------------------
- ----------------------------------------------------------------------------------- */
-
-
- #include "SWTranslucentBlitters.h"
-
-
- #pragma mark -----Public API-----
- ///--------------------------------------------------------------------------------------
- // Setting and Getting translucency level
- ///--------------------------------------------------------------------------------------
-
- SW_FUNC OSErr SWSetSpriteTranslucencyLevel(
- SpritePtr srcSpriteP,
- unsigned long level)
- {
- short currentPixelDepth;
- OSErr err;
-
-
- currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
- err = kWrongDepthErr;
-
- srcSpriteP->translucencyLevel = level;
-
- if (currentPixelDepth == 8)
- {
- if ((level <= 0) || (level > gNumberOf8BitTranslucencyLevels)) {
- srcSpriteP->frameDrawProc = BlitPixie8BitMaskDrawProc;
- } else {
- srcSpriteP->translucencyLevel--;
- // preshift it
- srcSpriteP->translucencyLevel <<= 16;
- srcSpriteP->frameDrawProc = BlitPixie8BitTranslucentMaskDrawProc;
- }
- err = noErr;
- }
- else if (currentPixelDepth == 16)
- {
- if ((level <= 0) || (level >= kNumberOf16BitTranslucencyLevels)) {
- srcSpriteP->frameDrawProc = BlitPixieAllBitMaskDrawProc;
- } else {
- srcSpriteP->frameDrawProc = BlitPixie16BitTranslucentMaskDrawProc;
- }
- err = noErr;
- }
- SWSetStickyIfError( err );
- return err;
- }
-
-
- SW_FUNC unsigned long SWGetSpriteTranslucencyLevel(SpritePtr srcSpriteP) {
- short currentPixelDepth;
- currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
- if (currentPixelDepth == 8)
- if (srcSpriteP->frameDrawProc == BlitPixie8BitTranslucentMaskDrawProc)
- return ((srcSpriteP->translucencyLevel) >> 16) + 1;
- else
- return 0;
- else if (currentPixelDepth == 16)
- if (srcSpriteP->frameDrawProc == BlitPixie16BitTranslucentMaskDrawProc)
- return srcSpriteP->translucencyLevel;
- else
- return 0;
- else
- return 0;
- }
-
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- /// 8-Bit Routines
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
- #pragma mark -----8 Bit Table Management-----
-
- //-----------------------------------------------------------------------------
- // 8-bit Translucency Table Management
- //-----------------------------------------------------------------------------
-
- // The Lookup table which is indexed by a [translucencyLevel][sourceColor][translucentColor]
- // Note that all colors are 8-bit, so this thing is 64K * gNumberOf8BitTranslucencyLevels
- // For instance, 8 levels adds up to half a meg.
- unsigned char *g8BitTranslucencyTable = NULL;
-
- // Our array for storing the current CLUT in an easily accessible fashion.
- RGBColor kSystemColorArray[kNumberOfColors];
-
- // Number of Levels we currently support
- int gNumberOf8BitTranslucencyLevels = 0;
-
-
- ///--------------------------------------------------------------------------------------
- // -- SWLoadOrCreate8BitTranslucencyTable --
- ///--------------------------------------------------------------------------------------
- // This function may be called to get the translucency table in memory.
- // It either loads a premade table from the resource fork of the app,
- // or if it does not exist. calculates the table and saves it in the resource fork.
- // Note that each table is CLUT specific. Therefore, set the CLUT
- // before calling this.
- // To save development time, after this calculates and saves the table into the
- // TTAB resource of your application, go into resedit and copy the TTAB resource
- // from the application and paste it into your project's resource file. This way
- // the resource will get added to your application at link time and you won't have
- // to wait for it to recompute each time.
-
- OSErr SWLoadOrCreate8BitTranslucencyTable (int numberOfLevels) {
- OSErr tableAllocationErr = noErr;
- OSErr err = noErr;
-
- // Ignore if we've already done this.
- if (g8BitTranslucencyTable == NULL) {
-
- // First try loading the table from the resource fork.
- // Note we hard code it being in resource ID 128. If you want
- // to support multiple CLUTS, you can create multiple tables
- // and store them under different resource IDs and load them
- // when you load your CLUT. You of course have to precompute
- // these tables
-
- err = SWLoad8BitTranslucencyTable(128);
-
- // If there is an error or the number of levels doesn't match up,
- // then we have to compute it (which can take a little while)
- if ((err != noErr) || (numberOfLevels != gNumberOf8BitTranslucencyLevels)) {
- err = SWCreate8BitTranslucencyTable(numberOfLevels);
-
- // And save it when we're done
- if (err == noErr) {
- err = SWSave8BitTranslucencyTable(128);
- }
- }
- }
- return err;
- }
-
- ///--------------------------------------------------------------------------------------
- // -- SWDispose8BitTranslucencyTable --
- ///--------------------------------------------------------------------------------------
- // This function must be called to clear the table from memory.
-
- void SWDispose8BitTranslucencyTable(void)
- {
- // Only do this if we've created a table.
- if (g8BitTranslucencyTable != NULL)
- {
- DisposePtr((Ptr)g8BitTranslucencyTable);
- g8BitTranslucencyTable = NULL;
- gNumberOf8BitTranslucencyLevels = 0;
- }
- }
-
- ///--------------------------------------------------------------------------------------
- // -- SWCreate8BitTranslucencyTable --
- ///--------------------------------------------------------------------------------------
- // This function will allocate and compute a table with the specified number of levels.
-
-
- OSErr SWCreate8BitTranslucencyTable (int numberOfLevels) {
- OSErr tableAllocationErr = noErr;
- unsigned long arraySize;
-
- // If we've already done this, get rid of the old one
- if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
-
- // First we need to allocate the array.
- arraySize = numberOfLevels * 65536 * sizeof(unsigned char);
- g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
- tableAllocationErr = MemError();
-
- // If we were able to then we continue loading or creating
- // the table.
- if (tableAllocationErr == noErr) {
- // Store our number of levels
- gNumberOf8BitTranslucencyLevels = numberOfLevels;
-
- // so we load up the CLUT into an array so we have fast access to it.
- CreateCLUTTable();
- // We compute the table (albeit slowly)
- Calc8BitTranslucencyTable(numberOfLevels);
- }
-
- return tableAllocationErr;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SWLoad8BitTranslucencyTable
- ///--------------------------------------------------------------------------------------
- // This function will load the translucency table from a TTAB resource of the specified ID,
- // rather than recomputing it from scratch each time. Note that the first byte in the
- // resource specifies the number of levels of translucency.
-
- OSErr SWLoad8BitTranslucencyTable(short resourceID) {
- unsigned char **TranslucencyTableHandle;
- unsigned char *TranslucencyTableData;
- OSErr err = noErr;
- unsigned long arraySize;
-
- // If we've already done this, get rid of the old one
- if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
-
- // Try and get a handle on the stored table
- TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
- if (TranslucencyTableHandle == NULL)
- {
- err = ResError();
- if (err == noErr)
- err = resNotFound;
- }
-
- // If it's there then we copy it into our Array.
- if (err == noErr) {
- HLock((Handle)TranslucencyTableHandle);
- TranslucencyTableData = *TranslucencyTableHandle;
-
- // First store the number of translucency levels
- gNumberOf8BitTranslucencyLevels = *TranslucencyTableData++;
-
- // then create a new translucency table
- arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
- g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
- err = MemError();
-
- if (err == noErr) {
- // and copy the data into the translucency table array
- BlockMove(TranslucencyTableData,
- g8BitTranslucencyTable,
- arraySize);
- } else {
- gNumberOf8BitTranslucencyLevels = 0;
- g8BitTranslucencyTable = NULL;
- }
- HUnlock((Handle)TranslucencyTableHandle);
- }
-
-
- // Then we free up our loaded table, because we've copied it to our array.
- if (TranslucencyTableHandle != NULL) {
- ReleaseResource((Handle)TranslucencyTableHandle);
- }
- // SWStickyErr not set, because an error might be expected, and mean
- // the TTAB has to be calculated
- return err;
- }
-
-
- ///--------------------------------------------------------------------------------------
- // SWSave8BitTranslucencyTable
- ///--------------------------------------------------------------------------------------
- // This function will save the translucency table from a TTAB resource of the specified ID,
- // so it can be loaded later. The format of the table is: the first byte is the number
- // of levels of translucency, the subsequent bytes are the table.
-
- OSErr SWSave8BitTranslucencyTable(short resourceID) {
- Boolean createdNewResource;
- OSErr err = noErr;
- unsigned long arraySize;
- unsigned char **TranslucencyTableHandle;
- unsigned char *TranslucencyTableData;
-
- // Make sure there is a Translucency Table to save
- if (g8BitTranslucencyTable == NULL)
- err = kNullTileMapErr;
-
- // Load or create the resource
- if (err == noErr) {
- arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
-
- // Check if the resource already exisits
- TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
-
- // If it already exists
- if (TranslucencyTableHandle != NULL) {
- SetHandleSize((Handle)TranslucencyTableHandle, arraySize + 1);
- err = MemError();
- // we free it up
- if (err != noErr)
- ReleaseResource((Handle)TranslucencyTableHandle);
-
- createdNewResource = false;
- }
- // If it doesn't exist, we get some memory so we can create it
- else if (ResError() == resNotFound || ResError() == noErr) {
- TranslucencyTableHandle = (unsigned char **)NewHandle(arraySize + 1);
- err = MemError();
- createdNewResource = true;
- }
- else
- err = ResError();
- }
- // Copy the data into the resource handle
- if (err == noErr) {
- HLock((Handle)TranslucencyTableHandle);
- if (createdNewResource) {
- AddResource((Handle)TranslucencyTableHandle, 'TTAB', resourceID, "\p");
- err = ResError();
-
- HLock((Handle)TranslucencyTableHandle);
- TranslucencyTableData = *TranslucencyTableHandle;
- *TranslucencyTableData = (unsigned char)gNumberOf8BitTranslucencyLevels;
- TranslucencyTableData++;
-
- // Copy the data from the translucency table array
- BlockMove(g8BitTranslucencyTable,
- TranslucencyTableData,
- arraySize);
-
- if (err != noErr)
- DisposeHandle((Handle)TranslucencyTableHandle);
-
- } else {
- // If there is an error, free everthing up.
- ChangedResource((Handle)TranslucencyTableHandle);
- err = ResError();
-
- if (err != noErr)
- ReleaseResource((Handle)TranslucencyTableHandle);
- }
- }
- // Update the resource file and clean up
- if (err == noErr) {
- UpdateResFile( CurResFile() );
- ReleaseResource((Handle)TranslucencyTableHandle);
- }
- SWSetStickyIfError(err);
- return err;
- }
-
- // End Public Functions
- // ------------------------------------------------------------------------------
-
-
-
-
- // ------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------
- // Our internal color table computation functions:
-
- // -- ColorToIndex --
- // Given an RGB triplet, determine which color in the current CLUT
- // is closest and return the index of that color.
- unsigned char ColorToIndex(long curRed, long curGreen, long curBlue) {
- unsigned long j, dist, bestDist;
- unsigned char bestMatch;
- long rr, gg, bb;
-
- bestDist = 0xFFFFFFFF;
-
- for (j=0; j < kNumberOfColors; j++) {
- rr = ABS(curRed - kSystemColorArray[j].red);
- gg = ABS(curGreen - kSystemColorArray[j].green);
- bb = ABS(curBlue - kSystemColorArray[j].blue);
- dist = rr + gg + bb;
- if (dist < bestDist) {
- bestMatch = j;
- bestDist = dist;
- }
- }
- return bestMatch;
- }
-
- // -- CalcNewColorValue --
- // Given two reds, greens or blues and a percent of translucency (from 0.0 to 1.0),
- // this calculates the blended version of the colors. This is the actual work of
- // computing the translucent color.
- long CalcNewColorValue (long sourceValue, long blendValue, float ratio) {
- float newValue = (ratio * (float)sourceValue) + ((1.0 - ratio) * (float)blendValue);
- return (long)newValue;
- }
-
- // -- Calc8BitTranslucencyTable --
- // internal function that does the work.
- void Calc8BitTranslucencyTable (int numberOfLevels) {
- long curRed, curGreen, curBlue;
- RGBColor curSourceColor, curBlendColor;
- long sourceColor, blendColor;
- long arrayIndex = 0;
- unsigned char newIndex;
- float curLevel, ratio;
- // For each level of translucency
- for (curLevel = 0.0; curLevel < numberOfLevels; curLevel += 1.0) {
- // We calculate the current translucency percentage (between 0.0 and 1.0)
- // (note we assume the user wants translucency levels evenly distributed
- // between (and not including) 0 and 1.
- ratio = ((curLevel + 1.0) / (numberOfLevels + 1.0));
- // For each of our 256 possible source background colors
- for (sourceColor = 0; sourceColor < kNumberOfColors; sourceColor++) {
- curSourceColor = kSystemColorArray[sourceColor];
- // For each of our 256 possible blended sprite colors
- for (blendColor = 0; blendColor < kNumberOfColors; blendColor++) {
- curBlendColor = kSystemColorArray[blendColor];
- // Calculate the value of the blended R, G, and B
- curRed = CalcNewColorValue(curSourceColor.red, curBlendColor.red, ratio);
- curGreen = CalcNewColorValue(curSourceColor.green, curBlendColor.green, ratio);
- curBlue = CalcNewColorValue(curSourceColor.blue, curBlendColor.blue, ratio);
- // And find the nearest color in our 256 color CLUT
- newIndex = ColorToIndex(curRed, curGreen, curBlue);
- // And store it in our table
- g8BitTranslucencyTable[arrayIndex] = newIndex;
- arrayIndex++;
- }
- }
- }
- }
-
-
- // -- CreateCLUTTable --
- // This function loads the current CLUT into an array that we use
- // when building our table.
- void CreateCLUTTable(void) {
- GWorldPtr theWorld;
- GDHandle theDevice;
- short i;
- PixMapHandle thePixMap;
- GetGWorld(&theWorld, &theDevice);
- thePixMap = GetGWorldPixMap(theWorld);
- for (i=0;i<kNumberOfColors;i++) {
- kSystemColorArray[i] = ((*((*thePixMap)->pmTable))->ctTable[i]).rgb;
- }
- }
-
-
- #pragma mark -----8 Bit Drawing-----
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- /// 8 Bit drawing
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
-
-
- extern SInt8 gSWmmuMode;
- extern SpritePtr gCurrentSpriteBeingDrawn;
-
- ///--------------------------------------------------------------------------------------
- // BlitPixie8BitTranslucentMaskDrawProc
- ///--------------------------------------------------------------------------------------
- /// Same as BlitPixie8BitMaskDrawProc, only we take a translucent value
- /// and pass it to our translucent draw function.
- /// (How I miss decent macro facilities).
-
- SW_FUNC void BlitPixie8BitTranslucentMaskDrawProc(
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long numBytesPerRow;
- unsigned long srcBaseOffset;
- unsigned long translucencyLevel = 0;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT(srcFrameP->maskPort != NULL);
- SW_ASSERT(g8BitTranslucencyTable != NULL);
-
- if (gCurrentSpriteBeingDrawn != NULL)
- translucencyLevel = gCurrentSpriteBeingDrawn->translucencyLevel;
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top -
- srcFrameP->frameRect.top] + srcBlitRect.left;
-
- // calculate the number of bytes in a row
- numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
-
- BlitPixieTranslucentMask8Bit(
- // calculate the address of the first byte of the source
- (PixelPtr)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (PixelPtr)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
-
- // calculate the address of the first byte of the mask
- (PixelPtr)(srcFrameP->maskBaseAddr + srcBaseOffset),
-
- // calculate the number of rows to blit
- dstBlitRect.bottom - dstBlitRect.top,
-
- // number of bytes in a row
- numBytesPerRow,
-
- // for PPC, just frameRowBytes
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
- //Translucency Level
- translucencyLevel
- );
-
- END_32_BIT_MODE
- }
-
- ///--------------------------------------------------------------------------------------
- // TranslucencyConvertChar
- ///--------------------------------------------------------------------------------------
- // Blends a single pixel.
-
- unsigned char SWInline TranslucencyConvertChar (
- register unsigned char srcPixel,
- register unsigned char destPixel,
- register unsigned long maskPixel,
- register unsigned char *tableAtLevel) {
-
- // If we are to draw it...
- if (! (maskPixel))
- // we need to generate an index of [source pixel][destination pixel]
- // into our lookup table. The fastest way is to bitshift the source
- // and OR it. This generates a sixteen bit number, whose high eight bits
- // are the source pixel and whose low eight bits are the destination pixel.
- return tableAtLevel[((srcPixel << 8) | destPixel)];
- else
- // otherwise, the mask says not to draw anything.
- return destPixel;
- }
-
- ///--------------------------------------------------------------------------------------
- // TranslucencyConvertLong
- ///--------------------------------------------------------------------------------------
- // Blends four 8-bit pixels at a time. Takes a source and destination long and generates
- // a new long representing the four pixels after blending.
-
- #if USE_PPC_ASSEMBLY && __MWERKS__ >= 0x1800
- // If we are on PPC and CW Pro, we inline some assembly to minimize the number of instructions
- // per pixel. The PPC can rotate, mask and splice the result all in one instruction.
- // This speeds this function up by about 10-15%
-
- unsigned long SWInline TranslucencyConvertLong (
- register unsigned long srcPixel,
- register unsigned long destPixel,
- register unsigned long maskPixel,
- register unsigned char *tableAtLevel) {
-
- register unsigned long curSrc, colorValue;
- // Do the first pixel (bits 24-31)
- // We do this in an analogous way to the way we do a single pixel
- // in TranslucencyConvertChar. The only difference is that we have
- // to mask off the pixels (using AND) and shift them around different
- // amounts so we can generate our 16 bit index.
- // N.B. That each of these four operations compiles to a single PPC instruction.
- if (! (maskPixel & 0xFF000000)) { // is this pixel part of our sprite
- curSrc = ((srcPixel >> 16) & 0x0000FF00); // shift the source pixel over to be the high byte of our 16 bit index
- __rlwimi(curSrc, destPixel, 8, 24, 31); // shift the destination pixel over so it's the low byte of our 16 bit index
- // combine them into one index
- colorValue = tableAtLevel[curSrc]; // look up the resulting pixel
- __rlwimi(destPixel, colorValue, 24, 0, 7); // and shift it back into place as our high end pixel
- }
-
- // Do the second pixel (bits 16-23) in a similar manner.
- if (! (maskPixel & 0x00FF0000)) {
- curSrc = ((srcPixel >> 8) & 0x0000FF00);
- __rlwimi( curSrc, destPixel, 16, 24, 31 );
- colorValue = tableAtLevel[curSrc];
- __rlwimi( destPixel, colorValue, 16, 8, 15 );
- }
-
- // Do the third pixel (bits 8-15) in a similar manner.
- if (! (maskPixel & 0x0000FF00)) {
- curSrc = (srcPixel & 0x0000FF00);
- __rlwimi( curSrc, destPixel, 24, 24, 31 );
- colorValue = tableAtLevel[curSrc];
- __rlwimi( destPixel, colorValue, 8, 16, 23 );
- }
-
- // Do the fourth pixel (bits 0-7) in a similar manner.
- if (! (maskPixel & 0x000000FF)) {
- curSrc = (srcPixel & 0x000000FF) << 8;
- __rlwimi( curSrc, destPixel, 0, 24, 31 );
- colorValue = tableAtLevel[curSrc];
- __rlwimi( destPixel, colorValue, 0, 24, 31 );
- }
-
- // return the four pixels we've computed
- return destPixel;
- }
-
- #else
-
- unsigned long SWInline TranslucencyConvertLong (
- register unsigned long srcPixel,
- register unsigned long destPixel,
- register unsigned long maskPixel,
- register unsigned char *tableAtLevel) {
- register unsigned long curSrc, curDest;
- register unsigned long colorValue;
- register unsigned long result = 0L;
- register unsigned long index;
-
- // Do the first pixel (bits 24-31)
- // We do this in an analogous way to the way we do a single pixel
- // in TranslucencyConvertChar. The only difference is that we have
- // to mask off the pixels (using AND) and shift them around different
- // amounts so we can generate our 16 bit index.
- if (! (maskPixel & 0xFF000000)) { // is this pixel part of our sprite
- curSrc = ((srcPixel >> 16) & 0x0000FF00); // shift the source pixel over to be the high byte of our 16 bit index
- curDest = destPixel >> 24; // shift the destination pixel over so it's the low byte of our 16 bit index
- index = curSrc | curDest; // combine them into one index
- colorValue = tableAtLevel[index]; // look up the resulting pixel
- result = colorValue << 24; // and shift it back into place as our high end pixel
- } else result = (destPixel & 0xFF000000);
-
- // Do the second pixel (bits 16-23) in a similar manner.
- if (! (maskPixel & 0x00FF0000)) {
- curSrc = ((srcPixel >> 8) & 0x0000FF00);
- curDest = (destPixel >> 16) & 0x000000FF;
- index = curSrc | curDest;
- colorValue = tableAtLevel[index];
- result = (colorValue << 16) | result;
- } else result |= (destPixel & 0x00FF0000);
-
- // Do the third pixel (bits 8-15) in a similar manner.
- if (! (maskPixel & 0x0000FF00)) {
- curSrc = (srcPixel & 0x0000FF00);
- curDest = (destPixel >> 8) & 0x000000FF;
- index = curSrc | curDest;
- colorValue = tableAtLevel[index];
- result = (colorValue << 8) | result;
- } else result |= (destPixel & 0x0000FF00);
-
- // Do the fourth pixel (bits 0-7) in a similar manner.
- if (! (maskPixel & 0x000000FF)) {
- curSrc = (srcPixel & 0x000000FF) << 8;
- curDest = (destPixel & 0x000000FF);
- index = curSrc | curDest;
- colorValue = tableAtLevel[index];
- result = colorValue | result;
- } else result = (destPixel & 0x000000FF) | result;
-
- // return the four pixels we've computed
- return result;
- }
-
- #endif
-
- ///--------------------------------------------------------------------------------------
- // BlitPixieTranslucentMask8Bit
- ///--------------------------------------------------------------------------------------
- // Modified version of SpriteWorld's standard 8-bit blitter.
- // Note that translucencyLevel is preshifted in this case << 16.
- // This is so we can OR it with the source and dest pixels in our conversion
-
- SW_FUNC void BlitPixieTranslucentMask8Bit(
- register PixelPtr srcPixelP,
- register PixelPtr dstPixelP,
- register PixelPtr maskPixelP,
- register unsigned long rowsToCopy,
- register unsigned long numBytesPerRow,
- register unsigned long srcOffset,
- register unsigned long dstOffset,
- unsigned long translucencyLevel)
- {
- register long index;
- register PixelPtr startSrcPixelP;
- register PixelPtr startDstPixelP;
- register PixelPtr startMaskPixelP;
-
- // Since we know the level of translucency, we go to that levels 256x256 table.
- // By doing this here, we only have to do it once. Now a sixteen bit index
- // we let us find the proper color (i.e. [sourceColorByte][destColorByte])
- register unsigned char *tableAtLevel = &g8BitTranslucencyTable[translucencyLevel];
-
- startSrcPixelP = srcPixelP;
- startDstPixelP = dstPixelP;
- startMaskPixelP = maskPixelP;
-
- while (rowsToCopy--)
- {
- register fourblits = (numBytesPerRow >> 2);
-
- srcPixelP = startSrcPixelP;
- dstPixelP = startDstPixelP;
- maskPixelP = startMaskPixelP;
-
- for (index = 0; index < fourblits; index++) {
- register unsigned long temp1;
- // For these four pixels, do the lookups to figure out the
- // pixels that need to be put on the screen.
- temp1 = TranslucencyConvertLong (srcPixelP[index],
- dstPixelP[index],
- maskPixelP[index],
- tableAtLevel);
- // And blit it.
- dstPixelP[index] = temp1;
- }
- srcPixelP += fourblits;
- dstPixelP += fourblits;
- maskPixelP += fourblits;
-
- // If we have any leftover pixels, do them.
- // note we could speed this case up by making a TranslucencyConvertWord
- if (numBytesPerRow & 0x2) {
- register unsigned char temp1;
-
- #ifdef __MWERKS__ // Do it nicely
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++,
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP)++,
- tableAtLevel);
- (*((unsigned char *) dstPixelP)++) = temp1;
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++,
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP)++,
- tableAtLevel);
- (*((unsigned char *) dstPixelP)++) = temp1;
- #else //Do the simplified (and slower) ThinkC way
-
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP),
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP),
- tableAtLevel);
- (*((unsigned char *) dstPixelP)) = temp1;
-
- // this painfully convoluted syntax is required to make ThinkC 6/7 happy
- srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
- dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
- maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
-
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP),
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP),
- tableAtLevel);
- (*((unsigned char *) dstPixelP)) = temp1;
-
- srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
- dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
- maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
- #endif
- }
- if (numBytesPerRow & 0x1) {
- register unsigned char temp1;
- #ifdef __MWERKS__ // Do it nicely
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++,
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP)++,
- tableAtLevel);
- (*((unsigned char *) dstPixelP)++) = temp1;
-
- #else //Do the simplified (and slower) ThinkC way
- temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP),
- *((unsigned char *) dstPixelP),
- *((unsigned char *) maskPixelP),
- tableAtLevel);
- (*((unsigned char *) dstPixelP)) = temp1;
-
- srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
- dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
- maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
- #endif
- }
-
- // bump to next row
- startSrcPixelP = (PixelPtr)(((char*)startSrcPixelP) + srcOffset);
- startDstPixelP = (PixelPtr)(((char*)startDstPixelP) + dstOffset);
- startMaskPixelP = (PixelPtr)(((char*)startMaskPixelP) + srcOffset);
- }
- }
-
- // A useful helper function
- unsigned long Blend8BitPixels (int level, int source, int dest) {
- return g8BitTranslucencyTable[((level << 16) | (source << 8) | dest)];
- }
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- ///16 Bit Translucency Blitters
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
- #pragma mark -----16 Bit Table Management-----
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
- Ptr gStorageP = NULL;
- unsigned char *g16BitTranslucencyTable = NULL;
-
- OSErr SWCreate16BitTranslucencyTable( void )
- {
- register float alpha,beta,source_multiplied,source_intensity,destination_intensity;
- register long i;
- register unsigned char *table_ptr;
- OSErr err = noErr;
-
- if (g16BitTranslucencyTable != NULL)
- err = kAlreadyCalledErr;
-
- if (err == noErr)
- {
- // Put the table on a 64k boundary
- gStorageP = NewPtr(32768 + 65536); // 15 bits + 64K Boundary
- if (gStorageP == NULL)
- err = MemError();
- }
-
-
- if (err == noErr)
- {
- g16BitTranslucencyTable = table_ptr = (unsigned char*)(((long)gStorageP | 0xffff)+1);
-
- /* table lookup offset format: 15 bits
-
- a= alpha
- s= source channel
- d= dest channel
-
- [a][s][d]
-
- offset = aaaaasssssddddd
-
-
- Side note:
- offset=aaaaaXsssssddddd may be kinder on the cache.
- */
-
- for (i=0;i<kNumberOf16BitTranslucencyLevels;i++)
- {
- alpha = ((float)i)/((float)kNumberOf16BitTranslucencyLevels - 1.0);
- beta = 1.0 - alpha;
- for (source_intensity=0;source_intensity<kNumberOf16BitTranslucencyLevels;source_intensity+=1.0)
- {
- source_multiplied = source_intensity * alpha;
-
- for (destination_intensity=0; destination_intensity<kNumberOf16BitTranslucencyLevels; destination_intensity+=1.0)
- *table_ptr++ = source_multiplied + (destination_intensity * beta);
- }
- }
- }
-
- return err;
- }
-
- ///--------------------------------------------------------------------------------------
- // -- SWDispose16BitTranslucencyTable --
- ///--------------------------------------------------------------------------------------
- // This function must be called to clear the table from memory.
-
- void SWDispose16BitTranslucencyTable(void)
- {
- // Only do this if we've created a table.
- if (gStorageP != NULL)
- {
- DisposePtr((Ptr)gStorageP);
- gStorageP = NULL;
- g16BitTranslucencyTable = NULL;
- }
- }
-
-
- #pragma mark -----16 Bit Blitters-----
- ///--------------------------------------------------------------------------------------
- // BlitPixie16BitTranslucentMaskDrawProc
- ///--------------------------------------------------------------------------------------
-
- SW_FUNC void BlitPixie16BitTranslucentMaskDrawProc (
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long srcBaseOffset;
- unsigned long translucencyLevel = 0;
- unsigned long height;
- unsigned long width;
- unsigned long packedHeightAndWidth;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT(srcFrameP->maskPort != NULL);
- SW_ASSERT(g16BitTranslucencyTable != NULL);
-
- if (gCurrentSpriteBeingDrawn != NULL)
- translucencyLevel = gCurrentSpriteBeingDrawn->translucencyLevel;
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // Must be calculated *after* clipping the Sprite!
- height = dstBlitRect.bottom - dstBlitRect.top;
- width = dstBlitRect.right - dstBlitRect.left;
- packedHeightAndWidth = ((height & 0x0000FFFF) << 16) | (width & 0x0000FFFF);
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top -
- srcFrameP->frameRect.top] +
- (srcBlitRect.left << 1);
-
- // calculate the number of bytes in a row
-
- BlitPixieTranslucencyMask16Bit(
- g16BitTranslucencyTable,
-
- // calculate the address of the first byte of the source
- (short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (short *)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) +
- (dstBlitRect.left << 1)),
-
- // calculate the address of the first byte of the mask
- (short *)(srcFrameP->maskBaseAddr +
- srcBaseOffset),
-
- // the number of rows to blit and number of row bytes, packed together
- packedHeightAndWidth,
-
- // for PPC, just frameRowBytes
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
-
- translucencyLevel);
-
- END_32_BIT_MODE
- }
-
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
-
- #if USE_PPC_ASSEMBLY
-
- /*
- 16-Bit Masked Translucency Blitter
-
- Adapted from Alex Clarke's alphaBlend rect blitter.
- - Added masking
- - Adjusted it to deal with sprite world style sources
- - Packed Height and width so we only have 8 args
- - Wrote C version so it compiles on 68K.
-
- */
-
- // Some defines to make this easier to read
- #define lookup_offset1 alpha
- #define lookup_offset2 r11
- #define lookup_offset3 r12
- #define height r13
- #define width r14
- #define tmp1 r0
- #define tmp2 r31
- #define tmp3 r30
- #define mask_checker tmp3
-
- void asm BlitPixieTranslucencyMask16Bit (
- register unsigned char *lookup_ptr,
- register short *srcPtr,
- register short *dstPtr,
- register short *maskPtr,
- register unsigned long heightAndWidth,
- register long srcRowBytes,
- register long dstRowBytes,
- register long alpha
- ) {
-
- //store all our temp variables on the stack
- stw tmp2,-4(SP)
- stw tmp3,-8(SP)
- stw height,-12(SP)
- stw width,-16(SP)
- stw lookup_offset2,-20(SP)
- stw lookup_offset3,-24(SP)
-
- // Pull out the height and width
- // we pack these two into one because MWerks only allows us to have 8
- // function arguments declared as "register".
- rlwinm height, heightAndWidth,16, 16, 31
- rlwinm width, heightAndWidth, 0, 16, 31
-
- // We need to make the rowBytes be rowBytes - width because we are using
- // preincrements when getting and setting the pixels
- add tmp1, width, width //adjust for pixels being 2 bytes long
- sub srcRowBytes,srcRowBytes,tmp1 //calculateoffsets to the next row
- sub dstRowBytes,dstRowBytes,tmp1
-
- subi srcPtr,srcPtr,2 //adjust the pointers so we can use pre-increments
- subi maskPtr,maskPtr,2 //adjust the pointers so we can use pre-increments
- subi dstPtr,dstPtr,2
-
- // Set up the offsets into the blending table for each of our R, G, and B lookups
- // by setting the high order five bits to the alpha color
- // Note that these high order bits never get changed as we
- // work on our pixels, so the alpha (translucency level)
- // stays the same
- rlwinm lookup_offset3,alpha,10,17,21
- mr lookup_offset2,lookup_offset3
- mr lookup_offset1,lookup_offset3
-
- @yloop
- mtctr width //set the ctr to so we copy do WIDTH number of pixels
-
- @xloop
- lhzu tmp1,2(srcPtr) //load the source and destination colour
- lhz tmp2,2(dstPtr)
-
- lhzu mask_checker, 2(maskPtr) // load the mask
- cmpwi mask_checker, 0 // if it is not zero
- bne @skipBlittingThisPixel // then keep going
-
- rlwimi lookup_offset3,tmp1,5,22,26 //blue channel source
- rlwimi lookup_offset2,tmp1,0,22,26 //green channel source
- rlwimi lookup_offset1,tmp1,27,22,26 //red channel source
-
- rlwimi lookup_offset3,tmp2,0,27,31 //blue channel destination
- rlwimi lookup_offset2,tmp2,27,27,31 //green channel destination
- rlwimi lookup_offset1,tmp2,22,27,31 //red channel destination
-
- lbzx tmp3,lookup_ptr,lookup_offset3 //load blended blue channel
- lbzx tmp2,lookup_ptr,lookup_offset2 //load blended green channel
- lbzx tmp1,lookup_ptr,lookup_offset1 //load blended red channel
-
- rlwimi tmp3,tmp2,5,22,26 //insert green channel into result
- rlwimi tmp3,tmp1,10,17,21 //insert red channel into result
-
- sthu tmp3,2(dstPtr) //store result
-
- @endOfBlitXLoop
- bdnz @xloop // decrement the ctr and see if we're done
-
- // Now we move the pointers forward to the next row
- add srcPtr,srcPtr,srcRowBytes
- add dstPtr,dstPtr,dstRowBytes
- add maskPtr,maskPtr,srcRowBytes
-
- //and if we haven't finished, continue
- subi height,height,1
- cmpwi height,0
- bne @yloop
-
- lwz tmp2,-4(SP) //clean up, restore registers we've been using
- lwz tmp3,-8(SP)
- lwz height,-12(SP)
- lwz width,-16(SP)
- lwz lookup_offset2,-20(SP)
- lwz lookup_offset3,-24(SP)
-
-
- blr
-
- // Little subroutine to make sure to increment the dstPtr when
- // the mask tells us not to blit
- @skipBlittingThisPixel
- addi dstPtr, dstPtr, 2
- b @endOfBlitXLoop
- }
-
-
-
- #undef lookup_offset1
- #undef lookup_offset2
- #undef lookup_offset3
- #undef tmp1
- #undef tmp2
- #undef tmp3
- #undef mask_checker
- #undef width
- #undef height
-
-
- #else /* USE_PPC_ASSEMBLY */
-
- // here is a C version of the above function.
-
- void BlitPixieTranslucencyMask16Bit (
- register unsigned char *lookup_ptr,
- register short *srcPtr,
- register short *dstPtr,
- register short *maskPtr,
- register unsigned long heightAndWidth,
- register long srcRowBytes,
- register long dstRowBytes,
- register long alpha
- ) {
- register unsigned long height = heightAndWidth >> 16;
- register unsigned long width = heightAndWidth & 0x0000FFFF;
- register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red, counter;
- register unsigned long final_red, final_green, final_result;
- register short curSource, curDest, curMask;
-
- srcRowBytes -= width * 2;
- dstRowBytes -= width * 2;
-
- while (height > 0) {
- counter = width;
- while (counter > 0) {
- lookup_offset_blue = lookup_offset_green = lookup_offset_red = alpha << 10;
- curSource = *srcPtr++;
- curMask = *maskPtr++;
- curDest = *dstPtr;
- if (curMask == 0) {
- lookup_offset_blue |= (curSource << 5) & 0x03E0;
- lookup_offset_green |= curSource & 0x03E0;
- lookup_offset_red |= (curSource >> 5) & 0x03E0;
-
- lookup_offset_blue |= curDest & 0x001F;
- lookup_offset_green |= (curDest >> 5) & 0x001F;
- lookup_offset_red |= (curDest >> 10) & 0x001F;
-
- final_red = lookup_ptr[lookup_offset_red];
- final_green = lookup_ptr[lookup_offset_green];
- final_result = lookup_ptr[lookup_offset_blue];
-
- final_result |= final_green << 5;
- final_result |= final_red << 10;
-
- *dstPtr++ = final_result;
- } else {
- dstPtr++;
- }
- counter--;
- }
-
- #ifdef MWERKS
- (char *)srcPtr += srcRowBytes;
- (char *)maskPtr += srcRowBytes;
- (char *)dstPtr += dstRowBytes;
- #else
- srcPtr = (short *)(((char*)srcPtr) + srcRowBytes);
- dstPtr = (short *)(((char*)dstPtr) + dstRowBytes);
- maskPtr = (short *)(((char*)maskPtr) + srcRowBytes);
- #endif
-
- height--;
- }
-
- }
- #endif /* USE_PPC_ASSEMBLY */
-
-
- // A useful helper function
- unsigned long Blend16BitPixels (int level, int source, int dest) {
- register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red;
- register unsigned long final_red, final_green, final_result;
-
- lookup_offset_blue = lookup_offset_green = lookup_offset_red = level << 10;
-
- lookup_offset_blue |= (source << 5) & 0x03E0;
- lookup_offset_green |= source & 0x03E0;
- lookup_offset_red |= (source >> 5) & 0x03E0;
-
- lookup_offset_blue |= dest & 0x001F;
- lookup_offset_green |= (dest >> 5) & 0x001F;
- lookup_offset_red |= (dest >> 10) & 0x001F;
-
- final_red = g16BitTranslucencyTable[lookup_offset_red];
- final_green = g16BitTranslucencyTable[lookup_offset_green];
- final_result = g16BitTranslucencyTable[lookup_offset_blue];
-
- final_result |= final_green << 5;
- final_result |= final_red << 10;
-
- return final_result;
- }
-
-